<?php
/**
 * supply image upload, get, resize function.
 *
 * @package SGN_Core
 * @version $Id$
 * @author dangnh6, canhpc2
 *
 */
class SGN_UploadImage
{
	/*
	 * adapter to receive file.
	 * 
	 * @var Zend_File_Transfer_Adapter_Http
	 */
	var $adapter = null;
	/*
	 * Indicate whether to rename file or raise error if the name has already exist.
	 * 
	 * @default false
	 * 
	 * @var boolean
	 */
	var $renameIfDuplicate = false;
	/*
	 * Self property to store itself.
	 * 
	 * @var SGN_Upload
	 */
	static $_self;
	/**
     *
     * Constructor
     *
     */
    function __construct()
    {
        $this->adapter = $this->createFileTransferAdapter();
        $this->resetDefaultValidators();
    }
    public static function factory()
    {
    	if(self::$_self)
    		return self::$_self;
    	self::$_self = new self();
    	return self::$_self;
    }
    /**
     * upload image
     * @param string $image
     * @param string $path
     * @param string $newName
     * @return boolean
     */
    public function upload($image, $path, $newName = '')
    {
        
        if(! $newName) {
            $newName = $this->getEncodedFileName($image);
        }
        if(! self::createFolder($path)) {
            return false;
        }
        $this->adapter->addFilter('Rename', array('target' => $path . '/' . $newName));
        //add Exist validator
        $this->adapter->removeValidator('Zend_Validate_File_NotExists');
        $notExistValidator = new Zend_Validate_File_NotExists($path);
        $this->adapter->addValidator($notExistValidator, false, $path);
        if(!$this->adapter->isValid()){
            return false;
        }
        $this->adapter->receive();
        return true;
    }
    /**
     * @param string $controlName
     * @param string $path
     * @param string $newNames
     */
    public function uploadMultiFiles($controlName, $path, $newNames = array())
    {
        if(! self::createFolder($path)){
            return false;
        }
        $this->adapter->setDestination($path);
        $this->adapter->receive();
        $fileInfo = $this->adapter->getFileInfo();
        $success = array();
        $i = 0;
        foreach ($fileInfo as $info){
            try {
                if(!$newNames[$i]){
                    $newNames[$i] = $info['name'];
                }
                rename($info['tmp_name'], $path.''.$newNames[$i]);
                $success[$i] = true;
            } catch (Exception $e) {
                $success[$i] = false;                    
            }
            $i++;
        }
        return $success;
    }
    /**
     * count number of file have been upload.
     */
    public function getFileNames(){
        $fileInfo = $this->adapter->getFileInfo();
        foreach ($fileInfo as $info){
            $result[] = $info['name'];
        }
        return $result;
    }
    /**
     * remove all dot to secure upload image(like image.php.jpg to imagephp.jpg)
     * @param string $name
     */
    public static function removeDotFromImageName($name) {
        $splitName = explode('.', $name);
        $newName = '';
        if(count($splitName) == 1) {
            $newName .= $splitName[count($splitName) - 1];
        } else {
            for($i = 0; $i < (count($splitName) - 1) ; $i++) {
                $newName .= $splitName[$i];
            }
            $newName .= '.' . $splitName[count($splitName) - 1];
        }
        return $newName;
    }
    /**
     * resize image
     * @param int $width
     * @param int $height
     * @param string $path. current image path
     * @param string $name. current image name
     * @param boolean $deleteOldFile. Chose to delete old file in $newPath or not
     * @param string $newPath. New image path
     * @param string $newName. New image name
     * @return newPath if success , false if not
     */
    public function resize($width, $height, $path, $name, $deleteOldFile = false, $newPath = '', $newName ='')
    {
        /*
         * image
         */
        if(! $newPath) {
            $newPath = $path;
        }
        if(! $newName) {
            $newName = $name;
        }
        if(! self::createFolder($newPath)) {
            return false;
        }
        $oldFileName = $path . '/' . $name;
        try {
            $image = new Imagick($oldFileName);
            $originalWidth = $image->getimagewidth();
            $originalHeight = $image->getimageheight();
            $availableWidth = $originalWidth;
            $availableHeight = $originalHeight;
            $startx = 0;
            $starty = 0;
            $saveSucc = false;
            if(($originalWidth/$width) > ($originalHeight/$height)){
                $availableWidth = ($originalHeight * $width) / $height;
                $startx = ($originalWidth - $availableWidth) / 2;
            } else {
                $availableHeight = ($originalWidth * $height) / $width;
                $starty = ($originalHeight - $availableHeight) / 2;
            }
            //make a resized copy, $image_info[0] and [1] is old width and height
            $copyOfImage = clone $image;
            $copyOfImage->cropimage($availableWidth, $availableHeight, $startx, $starty);
            $copyOfImage->resizeImage($width, $height, imagick::FILTER_UNDEFINED, 1);
            /*
             * delete old file in $newPath
            */
            if($deleteOldFile) {
                $files = glob("$newPath/*"); // get all file names
                foreach($files as $file){ // iterate files
                    if(is_file($file))
                        unlink($file); // delete file
                }
            }
            //Save to disk
            $saveSucc = $copyOfImage->writeimage($newPath . '/' . $newName);
        } catch (Exception $e){
            return false;
        }
        return $newPath . '/' . $newName;
    }
    /**
     * check if file existed
     * @param string $path
     * @param string $name
     * @return boolean
     */
    public function checkFileExist($path, $name) {
        return file_exists($path . '/' . $name);
    }
    /**
     * Check if folder has existed, otherwise, create them.
     * @return true if success, otherwise, return false.
     * @param $path
     */
    public static function createFolder($path)
    {
        try{
            if(file_exists($path)){
                if(!is_dir($path)){
                    try {
                        unlink($path);
                        if(!mkdir($path, 0777, true)) {
                            return false;
                        }
                        if(!chmod($path, 0777)){
                            return false;
                        }
                    } catch (Exception $ex){
                        return false;
                    }
                }
            } else {
                if (!mkdir($path, 0777, true)){
                    return false;
                }
                if(!chmod($path, 0777)){
                    return false;
                }
            }
            if(is_writable($path)){
                return true;
            }
        } catch (Exception $ex){
            return false;
        }
        return false;
    }
    /**
     * create Zend File Transfer Adapter
     * 
     * @return Zend_File_Transfer_Adapter_Http
     */
	protected function createFileTransferAdapter()
    {
    	$adapter = new Zend_File_Transfer_Adapter_Http();
        return $adapter;
    }
    
    /**
     * Reset all validators to default state.
     * 
     * @return void
     */
    public function resetDefaultValidators()
    {
    	$this->clearValidators();
    	//add extension Validator.
        //$extensionValidator = new Zend_Validate_File_Extension('jpg,gif,png');
        //$this->adapter->addValidator($extensionValidator, false);
        //add Count validator
        $countValidator = new Zend_Validate_File_Count(1);
        $this->adapter->addValidator($countValidator, false, 1);
        //add Size validator
        $sizeValidator = new Zend_Validate_File_Size('5MB');
        $this->adapter->addValidator($sizeValidator, false);
    }
    /**
     * @param string $rootFolder, folder where to save all userFolder
     * @param integer $userId
     * @return string
     */
    public static function getFolderForProfile($rootFolder, $userId)
    {
        $folderName = array(
                            $userId % 100,
                            floor(($userId % 10000) / 100),
                            );
        $endFolder = $rootFolder . '/' . $folderName[0] . '/' . $folderName[1] . '/' . $userId;
        return $endFolder;
    }
    public static function deleteCacheForProfile($userId)
    {
        $cache = SGN_Application::loadCacheInstance('sgn', 'profile');
        $config = SGN_Application::getConfig('sgn', 'uploadimage', 'profile');
        $key = $config->cachePrefix . '.' . $userId;
        $cache->deleteCache($key);
    }
    /**
     * Get picture from $url, make some copies due to $sizeConfig and save them in $path
     *  
     * @param string $url
     * @param array $sizeConfig
     * @param string $path
     * @param string $newName
     * 
     * @return boolean
     */
    public function uploadFromUrl($url, $sizeConfig, $path, $name)
    {
       /*  $oldFileName = str_replace('profilepic', 'origin_profilepic', $path) . '/' . $name;
        file_put_contents($oldFileName, file_get_contents($url));
        $saveSucc = $this->resize($sizeConfig, $oldFileName, $path, $name);
        return $saveSucc; */
    }
    public function getEncodedFileName($controlName)
    {
    	return str_replace(' ', '_', $this->adapter->getFileName($controlName, false));
    }
    /**
     * @return array
     */
    public function getMessages()
    {
    	return $this->adapter->getMessages();
    }
    
    public function setRenameIfDuplicate($value)
    {
    	$this->renameIfDuplicate = $value;
    }
    
	public function getRenameIfDuplicate($value)
    {
    	return $this->renameIfDuplicate;
    }
    
    public function clearValidators()
    {
    	$this->adapter->clearValidators();
    }
    
    public function removeValidator($name)
    {
    	$this->adapter->removeValidator($name);
    }
    
    public function setFileType($types)
    {
    	$extensionValidator = new Zend_Validate_File_Extension($types);
        $this->adapter->addValidator($extensionValidator, false);
    }
    /**
     * set max size 
     * @param string $max. Ex: 5MB
     */
    public function setMaxSizeOnly($max)
    {
    	$sizeValidator = new Zend_Validate_File_Size(array ('max' => $max));
        $this->adapter->addValidator($sizeValidator, false);
    }
    /**
     * set min size
     * @param string $min. Ex: 1MB
     */
    public function setMinSizeOnly($min)
    {
    	$sizeValidator = new Zend_Validate_File_Size(array ('min' => $min));
        $this->adapter->addValidator($sizeValidator, false);
    }
    /**
     * set max and min size
     * @param string $max. Ex: 5MB
     * @param string $min. Ex: 1MB
     */
    public function setMinAndMax($min, $max)
    {
    	$sizeValidator = new Zend_Validate_File_Size(array ('min' => $min, 'max' => $max));
        $this->adapter->addValidator($sizeValidator, false);
    }
    
    /**
     * @param string $source_image Path of the source image
     * @param string $target_image Path of the target image
     * @param array $crop_area Array like array('left' => [LEFT], 'top' => [TOP],
     *                                          'width' => [WIDTH], => 'height' => [HEIGHT])
     * @param returrn 
     */
    public function cropImage($sourceImage, $targetImage, $cropArea, $deleteSourceFile = true){
        try {
            /**
             *  create imgick object.
             */
            $imagickObj = new Imagick($sourceImage);
            
            /**
             * crop image
             */
            if(isset($cropArea)){
                $imagickObj->cropimage($cropArea['width'], $cropArea['height'], $cropArea['left'], $cropArea['top']);
            }
            /**
             * wwrite to destination image
             */
            $imagickObj->writeimage($targetImage);
        } catch (Exception $e) {
            throw new Exception('Crop failed');
        }
        if($deleteSourceFile){
            unlink($sourceImage);
        }
        return true;
    }
    
    public static function generateFolderName($size){
        if(($size['width'] <= 0) || ($size['height']<=0)){
            throw new Exception("Size['width'=> ".$size['width'].", 'height' => ".$size['height']."] is invalid.");
        }
        return $size['width'].'x'.$size['height'];
    }
}